// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Antlr4.Runtime.Tree;

namespace SnapObjects.Expressions
{
    internal class NewExpressionVisitor<TContext> where TContext : IParseTree
    {
        private readonly IPolicyProvider<Expression> _provider;
        private readonly IExpressionVisitor<Expression> _visitor;


        public NewExpressionVisitor(
            IPolicyProvider<Expression> provider,
            IExpressionVisitor<Expression> treeVisitor)
        {
            _provider = provider;
            _visitor = treeVisitor;
        }

        public Expression Visit(TContext context, ParserOptions<Expression> options)
        {
            var properties = new List<DynamicProperty>();
            var expressions = new Dictionary<string, Expression>();

            var propertyContext = context.GetChild(2);
            var newOptions = _provider.NestParser.CreateOptions(options);

            for (var i = 0; i < propertyContext.ChildCount; i++)
            {
                var assign = propertyContext.GetChild(i);

                if (assign.ChildCount == 3)
                {
                    var name = assign.GetChild(0).GetText();

                    var value = _visitor.Visit(assign.GetChild(2), newOptions);

                    expressions.Add(name, value);

                    properties.Add(new DynamicProperty(name, value.Type));
                }
            }

            var type = DynamicFactory.Instance.GetDynamicClass(properties);

            MemberBinding[] bindings = expressions
                .Select(x => Expression.Bind(type.GetProperty(x.Key), x.Value))
                .ToArray();

            var expression = Expression.MemberInit(Expression.New(type), bindings);

            return _provider.NestParser.Invoke(options, expression, newOptions);
        }
    }
}
